package com.example.netty_pipline.pipeline;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 默认的ChannelPipeline实现
 * 模仿Netty的DefaultChannelPipeline，实现处理器链管理
 */
public class DefaultChannelPipeline implements ChannelPipeline {
    
    private final String name;
    private final Map<String, AbstractChannelHandlerContext> name2ctx = new ConcurrentHashMap<>();
    private final AbstractChannelHandlerContext head;
    private final AbstractChannelHandlerContext tail;
    
    public DefaultChannelPipeline(String name) {
        this.name = name;
        this.head = new HeadContext(this);
        this.tail = new TailContext(this);
        head.next = tail;
        tail.prev = head;
    }
    
    @Override
    public ChannelPipeline addFirst(String name, ChannelHandler handler) {
        checkDuplicateName(name);
        AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, name, handler);
        addFirst0(newCtx);
        return this;
    }
    
    @Override
    public ChannelPipeline addLast(String name, ChannelHandler handler) {
        checkDuplicateName(name);
        AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, name, handler);
        addLast0(newCtx);
        return this;
    }
    
    @Override
    public ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) {
        checkDuplicateName(name);
        AbstractChannelHandlerContext baseCtx = getContextOrThrow(baseName);
        AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, name, handler);
        addBefore0(baseCtx, newCtx);
        return this;
    }
    
    @Override
    public ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler) {
        checkDuplicateName(name);
        AbstractChannelHandlerContext baseCtx = getContextOrThrow(baseName);
        AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, name, handler);
        addAfter0(baseCtx, newCtx);
        return this;
    }
    
    @Override
    public ChannelPipeline remove(String name) {
        AbstractChannelHandlerContext ctx = name2ctx.get(name);
        if (ctx != null) {
            remove0(ctx);
        }
        return this;
    }
    
    @Override
    public ChannelPipeline remove(ChannelHandler handler) {
        AbstractChannelHandlerContext ctx = findContext(handler);
        if (ctx != null) {
            remove0(ctx);
        }
        return this;
    }
    
    @Override
    public ChannelHandler get(String name) {
        AbstractChannelHandlerContext ctx = name2ctx.get(name);
        return ctx != null ? ctx.handler() : null;
    }
    
    @Override
    public ChannelHandlerContext context(String name) {
        return name2ctx.get(name);
    }
    
    @Override
    public ChannelHandlerContext context(ChannelHandler handler) {
        return findContext(handler);
    }
    
    @Override
    public String name() {
        return name;
    }
    
    // 入站事件触发方法
    @Override
    public ChannelPipeline fireChannelActive() {
        head.fireChannelActive();
        return this;
    }
    
    @Override
    public ChannelPipeline fireChannelInactive() {
        head.fireChannelInactive();
        return this;
    }
    
    @Override
    public ChannelPipeline fireChannelRead(Object msg) {
        head.fireChannelRead(msg);
        return this;
    }
    
    @Override
    public ChannelPipeline fireChannelReadComplete() {
        head.fireChannelReadComplete();
        return this;
    }
    
    @Override
    public ChannelPipeline fireUserEventTriggered(Object evt) {
        head.fireUserEventTriggered(evt);
        return this;
    }
    
    @Override
    public ChannelPipeline fireExceptionCaught(Throwable cause) {
        head.fireExceptionCaught(cause);
        return this;
    }
    
    // 出站操作触发方法
    @Override
    public ChannelPipeline bind(Object localAddress) {
        tail.bind(localAddress);
        return this;
    }
    
    @Override
    public ChannelPipeline connect(Object remoteAddress, Object localAddress) {
        tail.connect(remoteAddress, localAddress);
        return this;
    }
    
    @Override
    public ChannelPipeline disconnect() {
        tail.disconnect();
        return this;
    }
    
    @Override
    public ChannelPipeline close() {
        tail.close();
        return this;
    }
    
    @Override
    public ChannelPipeline write(Object msg) {
        tail.write(msg);
        return this;
    }
    
    @Override
    public ChannelPipeline flush() {
        tail.flush();
        return this;
    }
    
    @Override
    public ChannelPipeline read() {
        tail.read();
        return this;
    }
    
    private void checkDuplicateName(String name) {
        if (name2ctx.containsKey(name)) {
            throw new IllegalArgumentException("Duplicate handler name: " + name);
        }
    }
    
    private void addFirst0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext nextCtx = head.next;
        newCtx.prev = head;
        newCtx.next = nextCtx;
        head.next = newCtx;
        nextCtx.prev = newCtx;
        
        name2ctx.put(newCtx.name(), newCtx);
        callHandlerAdded(newCtx);
    }
    
    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prevCtx = tail.prev;
        newCtx.prev = prevCtx;
        newCtx.next = tail;
        tail.prev = newCtx;
        prevCtx.next = newCtx;
        
        name2ctx.put(newCtx.name(), newCtx);
        callHandlerAdded(newCtx);
    }
    
    private void addBefore0(AbstractChannelHandlerContext baseCtx, AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prevCtx = baseCtx.prev;
        newCtx.prev = prevCtx;
        newCtx.next = baseCtx;
        baseCtx.prev = newCtx;
        prevCtx.next = newCtx;
        
        name2ctx.put(newCtx.name(), newCtx);
        callHandlerAdded(newCtx);
    }
    
    private void addAfter0(AbstractChannelHandlerContext baseCtx, AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext nextCtx = baseCtx.next;
        newCtx.prev = baseCtx;
        newCtx.next = nextCtx;
        baseCtx.next = newCtx;
        nextCtx.prev = newCtx;
        
        name2ctx.put(newCtx.name(), newCtx);
        callHandlerAdded(newCtx);
    }
    
    private void remove0(AbstractChannelHandlerContext ctx) {
        AbstractChannelHandlerContext prev = ctx.prev;
        AbstractChannelHandlerContext next = ctx.next;
        prev.next = next;
        next.prev = prev;
        
        name2ctx.remove(ctx.name());
        callHandlerRemoved(ctx);
    }
    
    private AbstractChannelHandlerContext getContextOrThrow(String name) {
        AbstractChannelHandlerContext ctx = name2ctx.get(name);
        if (ctx == null) {
            throw new IllegalArgumentException("No handler named " + name + " found");
        }
        return ctx;
    }
    
    private AbstractChannelHandlerContext findContext(ChannelHandler handler) {
        for (AbstractChannelHandlerContext ctx : name2ctx.values()) {
            if (ctx.handler() == handler) {
                return ctx;
            }
        }
        return null;
    }
    
    private void callHandlerAdded(AbstractChannelHandlerContext ctx) {
        try {
            ctx.handler().handlerAdded(ctx);
        } catch (Exception e) {
            fireExceptionCaught(e);
        }
    }
    
    private void callHandlerRemoved(AbstractChannelHandlerContext ctx) {
        try {
            ctx.handler().handlerRemoved(ctx);
        } catch (Exception e) {
            fireExceptionCaught(e);
        }
    }
    
    // 头处理器上下文
    private static class HeadContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
        
        HeadContext(ChannelPipeline pipeline) {
            super(pipeline, "head", null);
        }
        
        @Override
        public ChannelHandler handler() {
            return this;
        }
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive();
        }
        
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelInactive();
        }
        
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.fireChannelRead(msg);
        }
        
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelReadComplete();
        }
        
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            ctx.fireUserEventTriggered(evt);
        }
    }
    
    // 尾处理器上下文
    private static class TailContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler {
        
        TailContext(ChannelPipeline pipeline) {
            super(pipeline, "tail", null);
        }
        
        @Override
        public ChannelHandler handler() {
            return this;
        }
        
        @Override
        public void bind(ChannelHandlerContext ctx, Object localAddress) throws Exception {
            // 尾处理器，出站操作结束
        }
        
        @Override
        public void connect(ChannelHandlerContext ctx, Object remoteAddress, Object localAddress) throws Exception {
            // 尾处理器，出站操作结束
        }
        
        @Override
        public void disconnect(ChannelHandlerContext ctx) throws Exception {
            // 尾处理器，出站操作结束
        }
        
        @Override
        public void close(ChannelHandlerContext ctx) throws Exception {
            // 尾处理器，出站操作结束
        }
        
        @Override
        public void write(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 尾处理器，出站操作结束
        }
        
        @Override
        public void flush(ChannelHandlerContext ctx) throws Exception {
            // 尾处理器，出站操作结束
        }
    }
}